package com.base.themvx.v

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.CallSuper
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.base.themvx.CL
import com.base.themvx.InvokeStep
import com.base.themvx.R
import com.base.themvx.isValidClick
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.listener.OnItemClickListener
import com.chad.library.adapter.base.listener.OnLoadMoreListener
import com.chad.library.adapter.base.module.LoadMoreModule
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.scwang.smart.refresh.header.MaterialHeader
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.scwang.smart.refresh.layout.api.RefreshLayout
import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener

/**
 ******************(^_^)***********************<br>
 * Author: fee(QQ/WeiXin:1176610771)<br>
 * <P>DESC:
 *　通用的列表数据的　ViewDelegate
 * </p>
 * ******************(^_^)***********************
 */
abstract class CommonListViewDelegate<ItemData>(context: Context) : BaseViewDelegate(context),
    OnRefreshLoadMoreListener,OnLoadMoreListener,OnItemClickListener,
    SuperEmptyLoadingView.IoptCallback{

    companion object Infos {
        const val LOAD_STAGE_INIT = "from_init"
        const val LOAD_STAGE_REFRESH = "from_refresh"
        const val LOAD_STAGE_LOADMORE = "from_loadmore"
    }

    /**
     * 当前的下拉刷新View
     */
    protected lateinit var mRefreshView: SmartRefreshLayout

    /**
     * 当前的数据列表　RecyclerView
     */
    protected lateinit var mRecyclerView: RecyclerView

    /**
     * 当前的数据集适配器
     */
    protected var mDataAdapter: BaseQuickAdapter<ItemData, out BaseViewHolder>? = null

    /**
     * 本内容视图的根控件/视图,为了便于子类使用　ViewBinding
     */
    protected lateinit var mContentView: ViewGroup

    /**
     * 空、加载中状态　视图
     */
    protected var mEmptyLoadingView: SuperEmptyLoadingView? = null

    /**
     * 数据列表有翻页需求时，加载第1面的页序，有的接口以　0为起始
     * def = 1
     */
    protected var mPageStartIndex = 1

    /**
     * 如果支持翻页，当前的页序
     * def = [mPageStartIndex]
     */
    protected var mCurPageIndex = mPageStartIndex

    /**
     * 如果支持翻页，每页获取的数据数量
     * def = 10
     */
    protected var mPerPageDataCount = 10

    /**
     * 是否启用下拉刷新
     * def = true
     */
    protected var mIsEnablePullRefresh = true

    /**
     * 刷新控件是否可以自动刷新了(有下拉刷新头部效果)
     * def = false: 目的是，初始化阶段：已经有了空布局的 loading并且加载数据中了，要先禁止刷新控件的自动刷新，
     *              不然在初始化时用户也可以下拉而触发下拉刷新了(导致又一次 加载数据)
     */
    protected var mIsCanAutoRefresh = false

    /**
     * 是否启用下拉刷新控件[SmartRefreshLayout] 的加载更多功能
     * def = false
     */
    protected var mIsEnableLoadMore = false

    /**
     * 是否启用本列表数据适配器的　上拉加载更多的功能
     * 注意：需要和　[mIsEnableLoadMore] 互斥
     * def = true
     */
    protected var mIsEnableAdapterLoadMore = true


    /**
     * 当翻页加载没有更多数据时，是否需要显示出没有更多数据的视图
     * def = true
     */
    protected var isNeedShowNoMoreDataView = true

    /**
     * 当列表没有更多数据时，并且当前列表数据不够一屏的情况下是否需要隐藏　提示没有更多数据　的视图
     * def = false
     */
    protected var mIsNeedHideNoMoreDataViewAtNotFullPage = false

    /**
     * 一些界面刚初始化时不需要 进行 loading的操作 可以设置为 false
     * def = true
     */
    protected var mIsNeedLoadingAtInit = true

    /**
     * 是否已经添加了空显示视图
     * def = false
     */
    protected var mIsAddedEmptyView = false

    /**
     * 当加载第1页数据就没有数据时，是否需要保留原来已有的数据
     * def = true: 保留原有数据
     */
    protected var mIsKeepDatasAt1stPageNoDatas = true

    /**
     * 当加载第1页数据并且有数据时，是否需要先把旧数据清空，再添加新数据
     * def = true: 需要清空数据,以完全加载新数据;　false: 不先清空旧数据，子类可能有其他的处理数据流程
     */
    protected var mIsNeedClearDatasAt1stPageHasDatas = true

    /**
     * 提供 的视图/布局资源 ID
     */
    override fun provideVLayoutRes(): Int {
        return R.layout.common_list_data_view
    }

    /**
     * 在该方法回调里初始化 Views
     * @param isInitState 是否为初始化状态,eg.: [Activity]的[onCreate]生命周期方法回调时；
     * @param dataIntent 从其他地方 跳转/路由 过来时所携带的 [Intent]
     * @param extraData 从其他地方 跳转/路由 过来时所携带的 [Bundle]数据； eg.: [Fragment]的初始化
     */
    override fun initViews(isInitState: Boolean, dataIntent: Intent?, extraData: Bundle?) {
        if (isInitState) {
            mRefreshView = view(R.id.refreshView)
            mRefreshView.setEnableRefresh(mIsCanAutoRefresh)
            if (mIsEnablePullRefresh){
                mRefreshView.setOnRefreshListener(this)
            }
            if (mIsEnableLoadMore){
                mRefreshView.setEnableLoadMore(true)
                mRefreshView.setOnLoadMoreListener(this)
            }
            //1
            initRefreshView()
            mRecyclerView = view(R.id.recyclerView)
            //2
            initRecyclerView()
            //3
            mDataAdapter = provideAdapter()
            mEmptyLoadingView = SuperEmptyLoadingView(mContext)
            if (mIsEnableAdapterLoadMore) {
                if (mDataAdapter is LoadMoreModule){
                    mDataAdapter?.loadMoreModule?.setOnLoadMoreListener(this)//设置了监听者同时也开启了功能
                }
            }
            if (!mIsEnablePullRefresh) {//没有启用下拉刷新，则如果加载数据失败情况下，需要点击空视图控件需要重新加载数据
                mEmptyLoadingView?.withOptCallback(this)
            }
            //一般列表　Item 都需要点击事件
            mDataAdapter?.setOnItemClickListener(this)
            mRecyclerView.adapter = mDataAdapter
            if (rootView is ViewGroup) {
                mContentView = rootView as ViewGroup
            }
//            mContentView = view(R.id.rootView)
            //4
            initListeners()
            if (mIsNeedLoadingAtInit){
                bindEmptyLoadingView(true)
            }
            //在初始化加载数据之前再回调一下 父类，让子类可以继续通过 [initView(isInitState)]函数初始化Views
            super.initViews(true, dataIntent, extraData)
            //5
            loadDatas(LOAD_STAGE_INIT)
        }
    }

    protected fun bindEmptyLoadingView(isThenLoading: Boolean){
        if (mIsAddedEmptyView){
            return
        }
        mIsAddedEmptyView = true
        mDataAdapter?.setEmptyView(mEmptyLoadingView!!)
        if (isThenLoading){
            mEmptyLoadingView?.loading()
        }
    }
    /**
     * 1: 子类差异化初始化本界面的　刷新控件　[SmartRefreshLayout]
     * 2: 初始化阶段：基类默认先把 下拉刷新控件的可下拉刷新禁用掉，以防止用户立即触发下拉刷新，导致重新 加载数据
     */
    @InvokeStep(1, desc = "子类差异化初始化本界面的　刷新控件　[SmartRefreshLayout]")
    protected open fun initRefreshView() {
        mIsCanAutoRefresh = false
        mRefreshView.setEnableRefresh(false)
        mRefreshView.setRefreshHeader(MaterialHeader(mContext, null))
    }

    /**
     * 2: 子类差异化初始化本界面的主　RecyclerView
     * 默认为　垂直方向的列表布局
     */
    @InvokeStep(2, desc = "子类差异化初始化本界面的主 RecyclerView ")
    protected open fun initRecyclerView(){
        mRecyclerView.layoutManager = LinearLayoutManager(mContext)
    }

    /**
     * 3: 子类提供具体的列表适配器
     */
    @InvokeStep(3, desc = "子类提供具体的列表适配器")
    protected abstract fun provideAdapter(): BaseQuickAdapter<ItemData,out BaseViewHolder>

    /**
     * 4: 初始化各数据监听者，或者其他监听者
     */
    @InvokeStep(4, desc = "初始化各数据监听者，或者其他监听者")
    protected open fun initListeners(){
        //here do nothing...
    }

    /**
     * 5: 请求加载数据，各子类重写实现业务逻辑
     * @param triggerFrom 触发的来源
     */
    @InvokeStep(5, desc = "请求加载数据，各子类重写实现业务逻辑")
    abstract fun loadDatas(triggerFrom: String)

    /**
     * 下拉刷新加载数据
     */
    open fun onPullRefresh() {
        mCurPageIndex = 1
        mEmptyLoadingView?.loading()
        loadDatas(LOAD_STAGE_REFRESH)
    }

    /**
     * 翻页加载更多/下一页　的数据
     */
    open fun onLoadMoreData() {
        mCurPageIndex ++
        loadDatas(LOAD_STAGE_LOADMORE)
    }

    /**
     * 添加子View　到本　根/内容　容器视图里
     * @param toAddView 要添加的View
     * @param configBlock ConstraintLayout.LayoutParams 在添加之前配置布局参数
     */
    protected fun addSubView(
        toAddView: View,
        configBlock: (ConstraintLayout.LayoutParams) -> Unit
    ) {
        if (toAddView.layoutParams != null){
            mContentView.addView(toAddView)
            return
        }
        val clp = CL(CL.WRAP_CONTENT, CL.WRAP_CONTENT)
        configBlock(clp)
        mContentView.addView(toAddView, clp)
    }

    /**
     * [SmartRefreshLayout] 触发的下拉刷新回调
     * @param refreshLayout 事件所属 RefreshLayout
     */
    override fun onRefresh(refreshLayout: RefreshLayout) {
        onPullRefresh()
    }

    /**
     * [SmartRefreshLayout] 触发的上拉加载更多回调
     * @param refreshLayout 事件所属 RefreshLayout
     */
    override fun onLoadMore(refreshLayout: RefreshLayout) {
        onLoadMoreData()
    }

    /**
     * [BaseQuickAdapter] 触发的上拉加载更多回调
     */
    override fun onLoadMore() {
        onLoadMoreData()
    }

    /**
     *　通用的处理加载数据结果
     * @param datasBelongPage 当前所加载的数据属于的页序
     * @param itemDatas 加载的列表数据
     * @param error 错误，异常信息
     */
    protected fun handleLoadDataResult(
        datasBelongPage: Int,
        itemDatas: List<ItemData>?,
        error: String?
    ) {
        val isLoadSuc = error.isNullOrBlank()
        if (!isLoadSuc){
            e(logMsg = "--> handleLoadDataResult() datasBelongPage = $datasBelongPage,error = $error")
        }
        val isHasDatas = !itemDatas.isNullOrEmpty()
        //是否没有更多数据了：加载成功但是没有数据集即为没有更多数据了
//        val isNoMoreDatas = isLoadSuc && itemDatas.isNullOrEmpty()
        val isNoMoreDatas = isLoadSuc && !isHasDatas
        if (datasBelongPage == 1){
            if (mIsEnablePullRefresh){//结束下拉刷新交互
                mIsCanAutoRefresh = true
                mRefreshView.setEnableRefresh(true)
                mRefreshView.finishRefresh(isLoadSuc)
            }
            if (isHasDatas){//响应有数据
                //清空旧数据集
                if (mIsNeedClearDatasAt1stPageHasDatas) {
                    mDataAdapter?.setList(null)
                }
//                clearDatasAt1stPageLoaded(true)
//                mDataAdapter?.setNewInstance(null)
                mEmptyLoadingView?.reset()
//                if (itemDatas!!.size < mPerPageDataCount){//??
//                    isNoMoreDatas = true
//                }
            } else {//响应没有数据
                if (isLoadSuc){
                    mEmptyLoadingView?.hintNoData()
                    if (!mIsKeepDatasAt1stPageNoDatas) {//数据接口加载成功，但是响应没有数据
                        mDataAdapter?.setList(null)
                    }
                } else {//加载异常
                    mEmptyLoadingView?.hintLoadFailure()
                    // TODO: 没有网络？？
//                    mEmptyLoadingView?.hintNoNetWork()
                }
            }
        } else {//第2页
            if (mIsEnableLoadMore){
                mRefreshView.finishLoadMore(isLoadSuc)
            } else {
                mDataAdapter?.let {adapter->
                    adapter.loadMoreModule.let {
                        if (!isNoMoreDatas){
                            if (isLoadSuc){
                                it.loadMoreComplete()
                            } else {
                                mCurPageIndex --;
                                it.loadMoreFail()
                            }
                        }
                    }
                }
            }
        }
        if (isHasDatas){
            val isAdded = notifyWillAddDatas(datasBelongPage,itemDatas!!)
            if (!isAdded) {
                mDataAdapter?.addData(itemDatas)
            }
            notifyAddedDatas(datasBelongPage)
        }
        if (isNoMoreDatas) {//请求第  1页数据的场景上也可以没有更多数据(没有第2页数据了)
            if (mIsEnableLoadMore) {
                mRefreshView.finishLoadMoreWithNoMoreData()
            } else {
                if (mIsEnableAdapterLoadMore) {
                    mDataAdapter?.loadMoreModule?.let {
                        if (!isNeedShowNoMoreDataView) {//不需要显示　没有更多数据　视图
                            it.loadMoreEnd(true)//则隐藏
                        } else {//需要显示提示没有更多数据的视图
                            if (!mIsNeedHideNoMoreDataViewAtNotFullPage) {
                                it.loadMoreEnd(false)//显示提示没有更多数据的视图
                            } else {
                                //判断是否在没有更多数据后，整个列表不够一屏
                                val isDataListFullPage = isDataListFullPage()
                                it.loadMoreEnd(!isDataListFullPage)
                            }
                        }
                    }
                }
            }
        }
    }

    protected open fun isDataListFullPage(): Boolean {
        mRecyclerView.layoutManager?.let {
            if (it is LinearLayoutManager) {
                val lm: LinearLayoutManager = it
                val totalDataCount = mDataAdapter?.itemCount ?: 0
                if (totalDataCount < 1) {
                    return false
                }
                val lastVisibleItemPos = lm.findLastCompletelyVisibleItemPosition()
                val firstVisiblePos = lm.findFirstCompletelyVisibleItemPosition()
                return (lastVisibleItemPos + 1) != totalDataCount || firstVisiblePos != 0
            }
        }
        return false
    }

    protected open fun clearDatasAt1stPageLoaded(isHasDatas: Boolean) {
        mDataAdapter?.setList(null)
    }

    /**
     * 在添加数据之前，通知将添加新数据
     * @return true: 本函数处理了，false: 未处理
     */
    protected open fun notifyWillAddDatas(datasBelongPage: Int, itemDatas: List<ItemData>):Boolean{
        //here do nothing...
        return false
    }

    /**
     * 在添加数据之后，通知已经增加了新数据
     */
    protected open fun notifyAddedDatas(datasBelongPage: Int){
        //here do nothing...
    }

    /**
     * 将本视图中列表　[mDataAdapter] 视为子类具体的适配器
     */
    protected fun <AD: BaseQuickAdapter<ItemData,out BaseViewHolder>> adapterAs(): AD? {
        return mDataAdapter as? AD
    }

    /**
     * 本视图层数据适配器　[BaseQuickAdapter] 的Item点击事件监听者回调
     * Callback method to be invoked when an item in this RecyclerView has
     * been clicked.
     *
     * @param adapter  the adapter
     * @param view     The itemView within the RecyclerView that was clicked (this
     * will be a view provided by the adapter)
     * @param position The position of the view in the adapter.
     */
    override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int) {
        //here do nothing...
    }


    protected fun addCommonHeaderView(isNeedAdjustRefreshViewLp: Boolean = true) {
        val headerViewRes = R.layout.common_header_view
        val headerView = LayoutInflater.from(mContext).inflate(headerViewRes, mContentView, false)
        addSubView(headerView) {
            it.topToTop = CL.PARENT_ID
            it.startToStart = CL.PARENT_ID
            it.endToEnd = CL.PARENT_ID
        }
        bindViewOnClickListener<View>(R.id.ivHeadBack)
        if (isNeedAdjustRefreshViewLp) {
            mRefreshView.updateLayoutParams<CL> {
                topToBottom = R.id.headerView
                topToTop = CL.UNSET
            }
        }
    }

    @CallSuper
    override fun onClick(v: View?) {
        if (R.id.ivHeadBack == v?.id){
            if (v.isValidClick()){
                reqHostFinish()
            }
        }
    }

    protected fun triggerAutoRefresh(){
        if (mIsEnablePullRefresh) {
            if (mIsCanAutoRefresh) {
                mRefreshView.autoRefresh()
            } else {
                onPullRefresh()
            }
        }
    }

    /**
     * 主要为本SuperEmptyLoadingView 在Loading之后的点击操作的回调，供外部作具体的处理
     * @param curLayoutStatus 当前的布局状态参见[LayoutStatus]
     */
    override fun optCallback(
        theEmptyLoadingView: SuperEmptyLoadingView?,
        curLayoutStatus: SuperEmptyLoadingView.LayoutStatus?
    ) {
        if (!mIsEnablePullRefresh) {
            onPullRefresh()
        }
    }
}